#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>

#include <time.h>
#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include "osa.h"
#include "UART.h"
#include "sockets.h"
#include "ip_addr.h"
#include "netdb.h"
#include "sys.h"
#include "sdk_api.h"
#include "guilin.h"

#define XMODEM_SOH 0x01
#define XMODEM_STX 0x02
#define XMODEM_EOT 0x04
#define XMODEM_ACK 0x06
#define XMODEM_NAK 0x15
#define XMODEM_CAN 0x18
#define XMODEM_CRC_CHR	'C'
#define XMODEM_CRC_SIZE 2		/* Crc_High Byte + Crc_Low Byte */
#define XMODEM_FRAME_ID_SIZE 2 		/* Frame_Id + 255-Frame_Id */
#define XMODEM_DATA_SIZE_SOH 128  	/* for Xmodem protocol */
#define XMODEM_DATA_SIZE_STX 1024 	/* for 1K xmodem protocol */
#define USE_1K_XMODEM 1  		/* 1 for use 1k_xmodem 0 for xmodem */
#define	TIMEOUT_USEC	0
#define	TIMEOUT_SEC		10

#if (USE_1K_XMODEM)
	#define XMODEM_DATA_SIZE 	XMODEM_DATA_SIZE_STX
	#define XMODEM_HEAD		XMODEM_STX
#else
	#define XMODEM_DATA_SIZE 	XMODEM_DATA_SIZE_SOH
	#define XMODEM_HEAD 		XMODEM_SOH
#endif


// debug uart log
#define sdk_uart_printf(fmt, args...) do { RTI_LOG("[ac_trace]"fmt, ##args); } while(0)
// CATStudio usb log
#define catstudio_printf(fmt, args...) do { CPUartLogPrintf("[ac_trace]"fmt, ##args); } while(0)

#define UPCASE( c ) ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c) )
#define sleep(x) OSATaskSleep((x) * 200)//second


extern OSMsgQRef uart3DataMsgQ;

static void uart3_thread(void);

// Device bootup hook before Phase1Inits.
// If you have some work to be init, you may implete it here.
// ex: you may start your task here. or do some initialize here.
extern void Phase1Inits_enter(void);
// Device bootup hook after Phase1Inits.
// If you have some work to be init, you may implete it here.
// ex: you may start your task here. or do some initialize here.
extern void Phase1Inits_exit(void);
// Device bootup hook before Phase2Inits.
// If you have some work to be init, you may implete it here.
// ex: you may start your task here. or do some initialize here.
extern void Phase2Inits_enter(void);
// Device bootup hook after Phase2Inits.
// If you have some work to be init, you may implete it here.
// ex: you may start your task here. or do some initialize here.
extern void Phase2Inits_exit(void);

int xmodem_send_bootloader(void);
int xmodem_send_firmware(void);
void char_to_hex(char * dest, unsigned char * src);
unsigned short get_crc16 ( unsigned char *ptr, unsigned short count);


void Phase1Inits_enter(void)
{
}

void Phase1Inits_exit(void)
{
}

void Phase2Inits_enter(void)
{
}

void Phase2Inits_exit(void)
{
    OSA_STATUS status;

    sdk_uart_printf("%s[%d]: starting...\n", __FUNCTION__, __LINE__);
    status = OSAMsgQCreate(&uart3DataMsgQ, "uart3DataMsgQ", sizeof(uart3DataParam), 1000, OS_FIFO);
    DIAG_ASSERT(status == OS_SUCCESS);

    sys_thread_new("uart3_thread", uart3_thread, NULL, DEFAULT_THREAD_STACKSIZE*4, 161);
}

static void uart_read(void)
{
	uart3DataParam uart3_temp;	
    OSA_STATUS status;
  	int i = -1;
	int ret = -1;
	int cot = -1;

    while (1) {
        memset(&uart3_temp, 0, sizeof(uart3DataParam));
        
        status = OSAMsgQRecv(uart3DataMsgQ, (UINT8 *)&uart3_temp, sizeof(uart3DataParam), OSA_SUSPEND);//recv data from uart
        
        if (status == OS_SUCCESS) {
            if (uart3_temp.UArgs) {
                sdk_uart_printf("%s[%d]: uart3_temp len:%d, data:%s\n", __FUNCTION__, __LINE__, uart3_temp.len, (char *)(uart3_temp.UArgs));
				
                // UART3_SEND_DATA((char *)(uart3_temp.UArgs),uart3_temp.len);
				
				free(uart3_temp.UArgs);
            }
        }
    }
}

/**
 * uart_read - uart read operation
 *
 */
static int uart_read_and_condition_search(char * condition, int len)
{
	uart3DataParam uart3_temp;	
    OSA_STATUS status;
  	int i = -1;
	int ret = -1;
	int cot = -1;


	 {
        memset(&uart3_temp, 0, sizeof(uart3DataParam));

		OSAMsgQPoll(uart3DataMsgQ,  &cot);
		sdk_uart_printf(" %s: cot = %d\n", __FUNCTION__, cot);
        
		for ( i = 0; i < cot; i++) {
			status = OSAMsgQRecv(uart3DataMsgQ, (UINT8 *)&uart3_temp, sizeof(uart3DataParam), OSA_SUSPEND);//recv data from uart
			
			if (status == OS_SUCCESS) {
				if (uart3_temp.UArgs) {
					sdk_uart_printf(" uart3_temp len:%d, data:%s\n", uart3_temp.len, (char *)(uart3_temp.UArgs));
	#if 1			
					if (strstr(uart3_temp.UArgs, condition) != NULL) 
						ret = 0;
					else 
						ret = -1;
	#endif				
					free(uart3_temp.UArgs);
				}
			}
		}
    }

	return ret;
}

enum ans_status {
	ANS_CRC = 1,
	ANS_ACK,
	ANS_NCK,
	ANS_EOT,
};

static int uart_read_and_condition_search_char(unsigned char * condition)
{
	uart3DataParam uart3_temp;	
    OSA_STATUS status;
  	int i = -1;
	int ret = -1;
	int cot = -1;

	OSAMsgQPoll(uart3DataMsgQ,  &cot);
	sdk_uart_printf(" %s: cot = %d\n", __FUNCTION__, cot);
        
	for ( i = 0; i < cot; i++) {
		memset(&uart3_temp, 0, sizeof(uart3DataParam));
		status = OSAMsgQRecv(uart3DataMsgQ, (UINT8 *)&uart3_temp, sizeof(uart3DataParam), OSA_SUSPEND);//recv data from uart
		
		if (status == OS_SUCCESS) {
			if (uart3_temp.UArgs) {
				sdk_uart_printf(" uart3_temp len:%d, data:%s\n", uart3_temp.len, (char *)(uart3_temp.UArgs));
	
				if (uart3_temp.UArgs[0] == 'C') {	/* XMODEM_CRC_CHR */
					condition[0] = 'C';
					ret = ANS_CRC;
				}
				else if (uart3_temp.UArgs[0] == 0x06) {		/* XMODEM_ACK */
					condition[0] = 0x06;
					ret = ANS_ACK;
				}
				else if (uart3_temp.UArgs[0] == 0x15) { 
					condition[0] = 0x15;
					ret = ANS_NCK;
				}
				else {
				
				}
		
				free(uart3_temp.UArgs);
			}
		}
	}

	return ret;
}

static void uart3_thread(void)
{
    uart3DataParam uart3_temp;	
	int complete = 0;

    UART_BaudRates baud;
	char * pdata = NULL;
	
	Guilin_Ldo_4_set(1); 

	/* init uart */
    UART3_ENABLE();	
    baud = UART3_GET_BAUD();	
	sdk_uart_printf(" %s: baud %d\n", __FUNCTION__, baud);

	sleep(3);

	/* set 6226 baudrate */
	pdata = "$CFGPRT,1,0,115200,3,3\n";	
	UART3_SEND_DATA(pdata, strlen(pdata));

	sleep(1);

	/* set device baudrate */
	UART3_SET_BAUD(UART_BAUD_115200);
    baud = UART3_GET_BAUD();	
	sdk_uart_printf(" %s: baud %d\n", __FUNCTION__, baud);

	sleep(1);

	uart_read();
	
	/* set 6226 reset */
	pdata = "$RESET,hf0,hff\n";
	UART3_SEND_DATA((unsigned char *)pdata, strlen(pdata));
	OSATaskSleep(10);


	while (!complete) {
		pdata = "M!T";
		UART3_SEND_DATA((unsigned char *)pdata, strlen(pdata));
		OSATaskSleep(1);
		//timerCountRead(50);

		if (uart_read_and_condition_search("YC", 1) == 0) {
			sdk_uart_printf(" %s\n", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
			complete = 1;
		}
		else
			sdk_uart_printf(" %s\n", "//////////////////////////////////");
	}

	
	sdk_uart_printf("%s", "download bootloader...\n");

	if (xmodem_send_bootloader() != 0) {
		sdk_uart_printf("%s", "xmodem error.\n");
	}


    /* set device baudrate */
	UART3_SET_BAUD(UART_BAUD_460800);
    baud = UART3_GET_BAUD();	
	sdk_uart_printf(" %s: baud %d\n", __FUNCTION__, baud);

	sleep(2);
	
	sdk_uart_printf("%s", "download bootloader success\n");
	sdk_uart_printf("%s", "Download firmware...\n");

	if (xmodem_send_firmware() != 0) {
		sdk_uart_printf("%s", "xmodem error.\n");
	}

	sdk_uart_printf(" %s\n", "Download firmware success\n");

	sleep(2);

#if 0
	pdata = "5\r\n";
	UART3_SEND_DATA((unsigned char *)pdata, strlen(pdata));
	OSATaskSleep(100);

	/* set 6226 reset */
	pdata = "$RESET,hf0,hff\n";
	UART3_SEND_DATA((unsigned char *)pdata, strlen(pdata));
	OSATaskSleep(10);
#endif

	 /* set device baudrate */
	UART3_SET_BAUD(UART_BAUD_115200);
    baud = UART3_GET_BAUD();	
	sdk_uart_printf(" %s: baud %d\n", __FUNCTION__, baud);

	sleep(2);

	Guilin_Ldo_4_set(1);
	sleep(2);
	SDK_GPS_ON_WITH_FIRMWARE();

	uart_read();

}

char bootloader[13][1024] = {
    
};


int xmodem_send_bootloader(void)
{
	//char packet_data[XMODEM_DATA_SIZE];		// 1024
	//char frame_data[XMODEM_DATA_SIZE + XMODEM_CRC_SIZE + XMODEM_FRAME_ID_SIZE + 1];		// 1024 + 2 + 2 + 1 = 1029
	unsigned char * packet_data;	
	unsigned char * frame_data;

	char complete;
	int retry_num,pack_counter,read_number = 0,write_number,i;
	unsigned short crc_value;
	unsigned char ack_id = 'C';
	int ret = -1;

	pack_counter = 0;	// 包计数器清零
	complete = 0;
	retry_num = 0;

	packet_data = malloc(XMODEM_DATA_SIZE);
	frame_data = malloc(XMODEM_DATA_SIZE + XMODEM_CRC_SIZE + XMODEM_FRAME_ID_SIZE + 1);

	memset(packet_data, 0, XMODEM_DATA_SIZE);
	memset(frame_data, 0, XMODEM_DATA_SIZE + XMODEM_CRC_SIZE + XMODEM_FRAME_ID_SIZE + 1);
	
	sdk_uart_printf(" %s\n", "Waiting for signal C/NAK!\n");
#if 1
	while(!complete)
	{
		ret = uart_read_and_condition_search_char(&ack_id);
			
		if (ret == ANS_CRC || ret == ANS_ACK || ret == ANS_NCK || ret == ANS_EOT) {
			sdk_uart_printf(" %s\n", "ccccccccccccccccccc");
			if (ack_id == 'C')
				complete = 1;
		}
	}

	complete = 0;
	while(!complete)
	{
		switch(ack_id)
		{
			case XMODEM_CRC_CHR:	// 接收到字符'C'开始启动传输，并使用CRC校验
				sdk_uart_printf(" %s", "begining to Send file ...\n");

			case XMODEM_ACK:        //0x06
				sdk_uart_printf(" %s\n", "XMODEM_ACK start...\n");
				retry_num = 0;
				pack_counter++;

				if(read_number < 13)//read_number为返回的读取实际字节数
				{
					sdk_uart_printf(" %s\n", "XMODEM_ACK.1..\n");

					frame_data[0] = XMODEM_HEAD;  // 帧开始字符
					frame_data[1] = (char)pack_counter;  // 信息包序号
					frame_data[2] = (char)(255 - frame_data[1]);  // 信息包序号的补码

					sdk_uart_printf(" %s\n", "XMODEM_ACK.2..\n");

					memcpy(packet_data, bootloader[read_number], XMODEM_DATA_SIZE);

					sdk_uart_printf(" %s\n", "XMODEM_ACK..3.\n");

					for(i=0; i < XMODEM_DATA_SIZE; i++)  // 128字节的数据段
						frame_data[i+3] = packet_data[i];//把收到的字符和信息头一起打包
					
					sdk_uart_printf(" %s\n", "XMODEM_ACK..4.\n");

					crc_value = get_crc16(packet_data, XMODEM_DATA_SIZE); // 16位crc校验
					frame_data[XMODEM_DATA_SIZE+3] = (unsigned char)(crc_value >> 8);// 高八位数据
					frame_data[XMODEM_DATA_SIZE+4] = (unsigned char)(crc_value);     //低八位数据

					sdk_uart_printf(" %s\n", "XMODEM_ACK..5.\n");

					/* 发送133字节数据 */
					UART3_SEND_DATA((unsigned char *)frame_data, XMODEM_DATA_SIZE + 5);	//向串口写一个包数据，即133字节数据
					read_number++;

					sdk_uart_printf(" %s\n", "XMODEM_ACK.6..\n");

					while(1)
					{
						ret = uart_read_and_condition_search_char(&ack_id);
			
						if (ret == ANS_CRC || ret == ANS_ACK || ret == ANS_NCK || ret == ANS_EOT) {
							sdk_uart_printf(" %s\n", "XMODEM_ACK   99999999");
							break;
						}
						OSATaskSleep(1);
					}

					if(ack_id == XMODEM_ACK) {
						;
					}
					else
					{
						sdk_uart_printf("%s\n","ACK Error!\n");
						sdk_uart_printf("ack_id = 0x%02X\n", ack_id);
					}
				}
				else  // 文件发送完成
				{
					ack_id = XMODEM_EOT;
					complete = 1;
					sdk_uart_printf("%s\n", "Complete ACK\n");

					while(ack_id != XMODEM_ACK)
					{
						ack_id = XMODEM_EOT;

						UART3_SEND_DATA(&ack_id, 1);	

						while(1)
						{
							ret = uart_read_and_condition_search_char(&ack_id);
				
							if (ret == ANS_CRC || ret == ANS_ACK || ret == ANS_NCK || ret == ANS_EOT) {
								sdk_uart_printf(" %s\n", "XMODEM_ACK   ************");
								break;
							}
							OSATaskSleep(1);
						}
					}
					sdk_uart_printf("%s\n", "Send file successful!!!\n");
					sleep(3);
				}
				break;

			case XMODEM_NAK:
				sdk_uart_printf(" %s\n", "XMODEM_NAK...\n");
				if( retry_num++ > 10)
				{
					printf("Retry too many times,Quit!\n");
					complete = 1;
				}
				else //重试，发送
				{
					UART3_SEND_DATA((unsigned char *)frame_data, XMODEM_DATA_SIZE + 5);

					while(1)
					{
						ret = uart_read_and_condition_search_char(&ack_id);
			
						if (ret == ANS_CRC || ret == ANS_ACK || ret == ANS_NCK || ret == ANS_EOT) {
							sdk_uart_printf(" %s\n", "XMODEM_NAK   zzzzzzzzzzzzz");
							break;
						}
						OSATaskSleep(1);
					}

					if( ack_id == XMODEM_ACK )
						sdk_uart_printf("%s\n", "OK\n");
					else
						sdk_uart_printf("%s\n", "Error!\n");
				}
				break;
			default:
				sdk_uart_printf("Fatal Error! %d\n", ack_id);
				complete = 1;
				return -1;
		}
	}
#endif
	return 0;
}

unsigned char firmware[258][1024] = {
   
};

#if 1
int xmodem_send_firmware(void)
{
	//char packet_data[XMODEM_DATA_SIZE];		// 1024
	//char frame_data[XMODEM_DATA_SIZE + XMODEM_CRC_SIZE + XMODEM_FRAME_ID_SIZE + 1];		// 1024 + 2 + 2 + 1 = 1029
	unsigned char * packet_data;	
	unsigned char * frame_data;

	int complete,retry_num,pack_counter,read_number = 0,write_number,i;
	unsigned short crc_value;
	unsigned char ack_id = 'C';
	int ret = -1;

	pack_counter = 0;	// 包计数器清零
	complete = 0;
	retry_num = 0;

	packet_data = malloc(XMODEM_DATA_SIZE);
	frame_data = malloc(XMODEM_DATA_SIZE + XMODEM_CRC_SIZE + XMODEM_FRAME_ID_SIZE + 1);

	memset(packet_data, 0, XMODEM_DATA_SIZE);
	memset(frame_data, 0, XMODEM_DATA_SIZE + XMODEM_CRC_SIZE + XMODEM_FRAME_ID_SIZE + 1);

	sdk_uart_printf(" %s\n", "Waiting for signal C/NAK!\n");

	while(!complete)
	{
		ret = uart_read_and_condition_search_char(&ack_id);
			
		if (ret == ANS_CRC || ret == ANS_ACK || ret == ANS_NCK || ret == ANS_EOT) {
			sdk_uart_printf(" %s\n", "ccccccccccccccccccccccccccccccccc");
			if (ack_id == 'C')
				complete = 1;
		}
	}

	complete = 0;
	while(!complete)
	{
		switch(ack_id)
		{
			case XMODEM_CRC_CHR:	// 接收到字符'C'开始启动传输，并使用CRC校验
				sdk_uart_printf(" %s", "begining to Send file ...\n");

			case XMODEM_ACK:        //0x06
				sdk_uart_printf(" %s\n", "XMODEM_ACK start...\n");
				retry_num = 0;
				pack_counter++;

				if(read_number < 258)//read_number为返回的读取实际字节数
				{
					sdk_uart_printf(" %s\n", "XMODEM_ACK.1..\n");

					frame_data[0] = XMODEM_HEAD;  // 帧开始字符
					frame_data[1] = (char)pack_counter;  // 信息包序号
					frame_data[2] = (char)(255 - frame_data[1]);  // 信息包序号的补码

					sdk_uart_printf(" %s\n", "XMODEM_ACK.2..\n");

					memcpy(packet_data, firmware[read_number], XMODEM_DATA_SIZE);

					sdk_uart_printf(" %s\n", "XMODEM_ACK..3.\n");

					for(i=0; i < XMODEM_DATA_SIZE; i++)  // 128字节的数据段
						frame_data[i+3] = packet_data[i];//把收到的字符和信息头一起打包
					
					sdk_uart_printf(" %s\n", "XMODEM_ACK..4.\n");

					crc_value = get_crc16(packet_data, XMODEM_DATA_SIZE); // 16位crc校验
					frame_data[XMODEM_DATA_SIZE+3] = (unsigned char)(crc_value >> 8);// 高八位数据
					frame_data[XMODEM_DATA_SIZE+4] = (unsigned char)(crc_value);     //低八位数据

					sdk_uart_printf(" %s\n", "XMODEM_ACK..5.\n");

					/* 发送133字节数据 */
					UART3_SEND_DATA((unsigned char *)frame_data, XMODEM_DATA_SIZE + 5);	//向串口写一个包数据，即133字节数据
					read_number++;

					sdk_uart_printf(" %s\n", "XMODEM_ACK.6..\n");

					while(1)
					{
						ret = uart_read_and_condition_search_char(&ack_id);
			
						if (ret == ANS_CRC || ret == ANS_ACK || ret == ANS_NCK || ret == ANS_EOT) {
							sdk_uart_printf(" %s\n", "XMODEM_ACK   99999999");
							break;
						}
						OSATaskSleep(1);
					}

					if(ack_id == XMODEM_ACK) {
						;
					}
					else
					{
						sdk_uart_printf("%s\n","ACK Error!\n");
						sdk_uart_printf("ack_id = 0x%02X\n", ack_id);
					}
				}
				else  // 文件发送完成
				{
					ack_id = XMODEM_EOT;
					complete = 1;
					sdk_uart_printf("%s\n", "Complete ACK\n");

					while(ack_id != XMODEM_ACK)
					{
						ack_id = XMODEM_EOT;

						UART3_SEND_DATA(&ack_id, 1);	

						while(1)
						{
							ret = uart_read_and_condition_search_char(&ack_id);
				
							if (ret == ANS_CRC || ret == ANS_ACK || ret == ANS_NCK || ret == ANS_EOT) {
								sdk_uart_printf(" %s\n", "XMODEM_ACK   ************");
								break;
							}
							OSATaskSleep(1);
						}
					}
					sdk_uart_printf("%s\n", "Send file successful!!!\n");					
				}
				break;

			case XMODEM_NAK:
				sdk_uart_printf(" %s\n", "XMODEM_NAK...\n");
				if( retry_num++ > 10)
				{
					printf("Retry too many times,Quit!\n");
					complete = 1;
				}
				else //重试，发送
				{
					UART3_SEND_DATA((unsigned char *)frame_data, XMODEM_DATA_SIZE + 5);

					while(1)
					{
						ret = uart_read_and_condition_search_char(&ack_id);
			
						if (ret == ANS_CRC || ret == ANS_ACK || ret == ANS_NCK || ret == ANS_EOT) {
							sdk_uart_printf(" %s\n", "XMODEM_NAK   zzzzzzzzzzzzz");
							break;
						}
						OSATaskSleep(1);
					}

					if( ack_id == XMODEM_ACK )
						sdk_uart_printf("%s\n", "OK\n");
					else
						sdk_uart_printf("%s\n", "Error!\n");
				}
				break;
			default:
				sdk_uart_printf("Fatal Error! %d\n", ack_id);
				complete = 1;
				return -1;
		}
	}

	return 0;
}

#endif


void char_to_hex(char * dest, unsigned char * src)
{
	int i;
	unsigned char hex = 0;
	int index = 0;

	for(i=0;i<strlen((char *)src);i=i+2)
	{
		if((src[i]>='0')&&(src[i]<='9'))
		{
			hex = (src[i]-'0')<<4;
		}
		else if((src[i]>='A')&&(src[i]<='F'))
		{
			hex = (src[i]-'A'+10)<<4;
		}

		if((src[i+1]>='0')&&(src[i+1]<='9'))
		{
			hex |= (src[i+1]-'0');
		}
		else if((src[i+1]>='A')&&(src[i+1]<='F'))
		{
			hex |= (src[i+1]-'A'+10);
		}

		dest[index++] = hex;
	}
}

unsigned short get_crc16 ( unsigned char *ptr, unsigned short count)
{
	unsigned short crc, i;

	crc = 0;
	while(count--)
	{
		crc = crc ^ (int) *ptr++ << 8;

		for(i = 0; i < 8; i++)
		{
			if(crc & 0x8000)
				crc = crc << 1 ^ 0x1021;
			else
				crc = crc << 1;
		}
	}

	return (crc & 0xFFFF);
}
